﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using System.Xml;


namespace Engine.Dtd.Schema {
    /// <summary>
    /// Represent a collection of DTD names.
    /// </summary>
    internal sealed class DNameCollection {
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal static readonly ICollection<DName> EmptySequence = new List<DName>(0);
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        internal XmlNameTable NameTable { get; private set; }
        [DebuggerBrowsable(DebuggerBrowsableState.Never)]
        private IDictionary<string, DName> buffer;

        public DNameCollection() {
            NameTable = new NameTable();
            buffer = new Dictionary<string, DName>(new DNameComparer());
            DName.CData = Add("CDATA");
            DName.PCData = Add("PCDATA");
            }

        class DNameComparer : IEqualityComparer<string> {
            public bool Equals(string x, string y) {
                return object.ReferenceEquals(x, y);
                }

            public int GetHashCode(string obj) {
                return obj.GetHashCode();
                }
            }

        /// <summary>
        /// Gets a DName object form a specified name.
        /// </summary>
        /// <param name="name">A string that represents a DTD name.</param>
        /// <returns>A DName object or null.</returns>
        public DName this[string name] {
            get {
                Guard.ArgumentNotNullOrEmpty(name, "name");
                string atomized = NameTable.Get(name);
                if (atomized == null)
                    return null;
                else
                    return buffer[atomized];
                }
            }

        public DName this[string name, bool caseSensitive] {
            get {
                Guard.ArgumentNotNullOrEmpty(name, "name");
                string atomized = NameTable.Get(name);
                if (atomized == null) {
                    if (caseSensitive)
                        return null;
                    atomized = NameTable.Get(name.ToUpperInvariant());
                    if (atomized == null) {
                        atomized = NameTable.Get(name.ToLowerInvariant());
                        if (atomized == null)
                            return null;
                        }
                    }
                return buffer[atomized];
                }
            }

        /// <summary>
        /// Releases all of DTD names that associated with a current schema.
        /// </summary>
        public void Clear() {
            NameTable = new NameTable();
            buffer.Clear();
            }

        /// <summary>
        /// Creates and adds a new DName object or returns existing one. 
        /// </summary>
        /// <param name="name">A string that reprecents a DName object.</param>
        /// <returns>The DName object</returns>
        public DName Add(string name) {
            Guard.ArgumentNotNullOrEmpty(name, "name");
            string atomized = NameTable.Get(name);
            if (atomized == null) {
                atomized = NameTable.Add(name);
                DName dname = new DName(atomized);
                buffer.Add(atomized, dname);
                return dname;
                }
            else
                return buffer[atomized];
            }
        }
    }
